/****************************************************************************
** Copyright (C) 2017 ZhouLiQiu(zhouliqiu@126.com).
**
** This file is part of the qtc_astyle, It is a plugin for Qt Creator.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is
** furnished to do so, subject to the following conditions:
**
** The above copyright notice and this permission notice shall be included in
** all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
** THE SOFTWARE.
**
****************************************************************************/
#include "valueaction.h"

#include <utils/qtcassert.h>

#include <QDebug>

#include <QAbstractButton>
#include <QGroupBox>
#include <QSpinBox>
#include <QComboBox>

namespace AStyle {
namespace Internal {

ValueAction::ValueAction(QObject *parent)
    : QAction(parent)
{
    m_widget = 0;
    connect(this, SIGNAL(triggered(bool)), this, SLOT(actionTriggered(bool)));
}

QString ValueAction::strStyle() const
{
    return m_strStyle;
}

void ValueAction::setStrStyle(QString strStyle)
{
    m_strStyle = strStyle;
}

QVariant ValueAction::value() const
{
    return m_value;
}

void ValueAction::setValue(const QVariant &value, bool doemit)
{
    if (value == m_value)
    {
        return;
    }
    m_value = value;
    if (this->isCheckable())
    {
        this->setChecked(m_value.toBool());
    }
    if (doemit)
    {
        emit valueChanged(m_value);
    }
}

QVariant ValueAction::defaultValue() const
{
    return m_defaultValue;
}

void ValueAction::setDefaultValue(const QVariant &value)
{
    m_defaultValue = value;
}

QString ValueAction::settingsKey() const
{
    return m_settingsKey;
}

void ValueAction::setSettingsKey(const QString &key)
{
    m_settingsKey = key;
}

void ValueAction::setSettingsKey(const QString &group, const QString &key)
{
    m_settingsKey = key;
    m_settingsGroup = group;
}

QString ValueAction::settingsGroup() const
{
    return m_settingsGroup;
}

void ValueAction::setSettingsGroup(const QString &group)
{
    m_settingsGroup = group;
}

QString ValueAction::toString() const
{
    return QLatin1String("value: ") + m_value.toString()
           + QLatin1String("  defaultvalue: ") + m_defaultValue.toString()
           + QLatin1String("  settingskey: ") + m_settingsGroup
           + QLatin1Char('/') + m_settingsKey;
}

void ValueAction::readSettings(const QSettings *settings)
{
    if (m_settingsGroup.isEmpty() || m_settingsKey.isEmpty())
    {
        return;
    }
    QVariant var = settings->value(m_settingsGroup + QLatin1Char('/') + m_settingsKey, m_defaultValue);
    if (isCheckable() && !var.isValid())
    {
        var = false;
    }
    setValue(var);
}

void ValueAction::writeSettings(QSettings *settings)
{
    if (m_settingsGroup.isEmpty() || m_settingsKey.isEmpty())
    {
        return;
    }
    settings->beginGroup(m_settingsGroup);
    settings->setValue(m_settingsKey, m_value);
    settings->endGroup();
}

void ValueAction::connectWidget(QWidget *widget)
{
    QTC_ASSERT(!m_widget,
               qDebug() << "ALREADY CONNECTED: " << widget << m_widget << toString(); return);
    m_widget = widget;

    if (QAbstractButton *button = qobject_cast<QAbstractButton *>(widget))
    {
        if (button->isCheckable())
        {
            button->setChecked(m_value.toBool());
            connect(button, SIGNAL(clicked(bool)), this, SLOT(checkableButtonClicked(bool)));
        }
    }
    else if (QSpinBox *spinBox = qobject_cast<QSpinBox *>(widget))
    {
        spinBox->setValue(m_value.toInt());
        connect(spinBox, SIGNAL(valueChanged(int)), this, SLOT(spinBoxValueChanged(int)));
        connect(spinBox, SIGNAL(valueChanged(QString)), this, SLOT(spinBoxValueChanged(QString)));
    }
    else if (QGroupBox *groupBox = qobject_cast<QGroupBox *>(widget))
    {
        if (!groupBox->isCheckable())
        {
            qDebug() << "connectWidget to non-checkable group box" << widget << toString();
        }
        groupBox->setChecked(m_value.toBool());
        connect(groupBox, SIGNAL(toggled(bool)), this, SLOT(groupBoxToggled(bool)));
    }
    else if (QComboBox *comboBox = qobject_cast<QComboBox *>(widget))
    {
        comboBox->setCurrentIndex(m_value.toInt());
        connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(comboBoxValueChanged(int)));
    }
    else
    {
        qDebug() << "Cannot connect widget " << widget << toString();
    }
}

void ValueAction::disconnectWidget()
{
    m_widget = 0;
}

void ValueAction::apply(QSettings *s)
{
    if (QAbstractButton *button = qobject_cast<QAbstractButton *>(m_widget))
    {
        setValue(button->isChecked());
    }
    else if (QSpinBox *spinBox = qobject_cast<QSpinBox *>(m_widget))
    {
        setValue(spinBox->value());
    }
    else if (const QGroupBox *groupBox = qobject_cast<QGroupBox *>(m_widget))
    {
        setValue(groupBox->isChecked());
    }
    else if (const QComboBox *comboBox = qobject_cast<QComboBox *>(m_widget))
    {
        setValue(comboBox->currentIndex());
    }
    if (s)
    {
        writeSettings(s);
    }
}

void ValueAction::checkableButtonClicked(bool)
{
    QAbstractButton *button = qobject_cast<QAbstractButton *>(sender());
    QTC_ASSERT(button, return);
    setValue(button->isChecked());
}

void ValueAction::spinBoxValueChanged(int value)
{
    QSpinBox *spinBox = qobject_cast<QSpinBox *>(sender());
    QTC_ASSERT(spinBox, return);
    setValue(value);
}

void ValueAction::spinBoxValueChanged(QString value)
{
    QSpinBox *spinBox = qobject_cast<QSpinBox *>(sender());
    QTC_ASSERT(spinBox, return);
    setValue(value);
}

void ValueAction::groupBoxToggled(bool checked)
{
    setValue(QVariant(checked));
}

void ValueAction::comboBoxValueChanged(int idx)
{
    QComboBox *comboBox = qobject_cast<QComboBox *>(sender());
    QTC_ASSERT(comboBox, return);
    setValue(idx);
}

void ValueAction::actionTriggered(bool)
{
    if (isCheckable())
    {
        setValue(isChecked());
    }
    if (actionGroup() && actionGroup()->isExclusive())
    {
        foreach (QAction * act, actionGroup()->actions())
        {
            if (ValueAction *dact = qobject_cast<ValueAction *>(act))
            {
                dact->setValue(bool(act == this));
            }
        }
    }
}

void ValueActionSet::insert(ValueAction *action, QWidget *widget)
{
    m_list.append(action);
    if (widget)
    {
        action->connectWidget(widget);
    }
}

void ValueActionSet::apply(QSettings *settings)
{
    foreach (ValueAction * action, m_list)
    {
        action->apply(settings);
    }
}

void ValueActionSet::finish()
{
    foreach (ValueAction * action, m_list)
    {
        action->disconnectWidget();
    }
}

QString ValueActionSet::searchKeyWords() const
{
    const QChar blank = QLatin1Char(' ');
    QString rc;
    foreach (ValueAction * action, m_list)
    {
        if (!rc.isEmpty())
        {
            rc += blank;
        }
        rc += action->text();
    }
    rc.remove(QLatin1Char('&'));
    return rc;
}

} // namespace Internal
} // namespace AStyle
